package tianrun.ziguan.api.calculate.config.service.sync.handler.asset;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import tianrun.ziguan.api.calculate.config.dto.request.*;
import tianrun.ziguan.api.calculate.config.dto.request.AssetIndicatorsInstanceVO;
import tianrun.ziguan.api.calculate.config.dto.request.common.DeleteBody;
import tianrun.ziguan.api.calculate.config.dto.response.TAssetCalLabelConfigVO;
import tianrun.ziguan.api.calculate.config.entity.*;
import tianrun.ziguan.api.calculate.config.enums.MoldEnum;
import tianrun.ziguan.api.calculate.config.service.asset.callabel.ITAssetCalLabelConfigService;
import tianrun.ziguan.api.calculate.config.service.asset.experssion.ITAssetExpressionService;
import tianrun.ziguan.api.calculate.config.service.asset.instance.ITAssetIndicatorsInstanceService;
import tianrun.ziguan.api.calculate.config.service.asset.module.ITAssetIndicatorsModuleService;
import tianrun.ziguan.api.calculate.config.service.cal.asset.ITCalAssetService;
import tianrun.ziguan.api.calculate.config.service.cal.label.ITCalLabelConfigService;
import tianrun.ziguan.api.calculate.config.service.common.CommonService;
import tianrun.ziguan.api.calculate.config.service.expression.ITExpressionService;
import tianrun.ziguan.api.calculate.config.service.sync.SyncType;
import tianrun.ziguan.api.calculate.config.service.sync.handler.AbstractSyncHandler;
import tianrun.ziguan.api.calculate.config.service.sync.handler.SyncHandler;
import tianrun.ziguan.api.calculate.config.service.template.instance.ITIndicatorsInstanceService;
import tianrun.ziguan.api.calculate.config.service.template.module.ITIndicatorsModuleService;
import tianrun.ziguan.api.calculate.config.utils.CollectionUtil;
import tianrun.ziguan.api.calculate.config.utils.MyBeanUtil;
import tianrun.ziguan.api.calculate.config.utils.Setter;
import tianrun.ziguan.api.common.util.ListUtil;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;

@Service
public class AssetIndicatorsModuleHandler extends AbstractSyncHandler {
    private final ITCalAssetService calAssetService;
    private final ITIndicatorsModuleService indicatorsModuleService;
    private final ITAssetIndicatorsModuleService assetIndicatorsModuleService;
    private final ITIndicatorsInstanceService indicatorsInstanceService;
    private final ITAssetIndicatorsInstanceService assetIndicatorsInstanceService;
    private final ITCalLabelConfigService calLabelConfigService;
    private final ITAssetCalLabelConfigService assetCalLabelConfigService;
    private final ITExpressionService expressionService;
    private final ITAssetExpressionService assetExpressionService;
    private final CommonService commonService;
    private final String instanceTableName = "t_asset_indicators_instance";
    private final String templateInstanceTableName = "t_indicators_instance";

    public AssetIndicatorsModuleHandler(ITCalAssetService calAssetService, ITIndicatorsModuleService indicatorsModuleService, ITAssetIndicatorsModuleService assetIndicatorsModuleService, ITIndicatorsInstanceService indicatorsInstanceService, ITAssetIndicatorsInstanceService assetIndicatorsInstanceService, ITCalLabelConfigService calLabelConfigService, ITAssetCalLabelConfigService assetCalLabelConfigService, ITExpressionService expressionService, ITAssetExpressionService assetExpressionService, CommonService commonService) {
        this.calAssetService = calAssetService;
        this.indicatorsModuleService = indicatorsModuleService;
        this.assetIndicatorsModuleService = assetIndicatorsModuleService;
        this.indicatorsInstanceService = indicatorsInstanceService;
        this.assetIndicatorsInstanceService = assetIndicatorsInstanceService;
        this.calLabelConfigService = calLabelConfigService;
        this.assetCalLabelConfigService = assetCalLabelConfigService;
        this.expressionService = expressionService;
        this.assetExpressionService = assetExpressionService;
        this.commonService = commonService;
    }

    @Override
    public MoldEnum mold() {
        return MoldEnum.CustomMeasure;
    }

    @Override
    public SyncType type() {
        return SyncType.ASSET;
    }

    /**
     * @param moduleIds 同一模板下不同组件的id
     * @param parentIds 资产id
     */
    @Override
    public void handler(Set<Long> moduleIds, Set<Long> parentIds) {
        Map<TAssetIndicatorsModule, List<TAssetIndicatorsInstance>> map = new HashMap<>();
        List<TCalAsset> calAssets = calAssetService.getByIds(parentIds);
        //1获取模板下的所有组件和实例
        List<TIndicatorsModule> sourceModules = indicatorsModuleService.getByIds(moduleIds);
        List<TIndicatorsInstance> sourceInstances = indicatorsInstanceService.listByModuleIds(moduleIds);
        List<CalLabelConfigVO> sourceLabelConfigs = calLabelConfigService.listVOByModuleIds(moduleIds, templateInstanceTableName);
        List<ExpressionVO> sourceExpressions = expressionService.listVOByModuleIds(moduleIds, templateInstanceTableName);

        Map<TIndicatorsModule, List<TIndicatorsInstance>> sourceMap = sourceModules.stream().collect(Collectors.toMap(Function.identity(), module -> sourceInstances.stream().filter(i -> Objects.equals(i.getModuleId(), module.getId())).collect(Collectors.toList())));
        Map<Long, TIndicatorsInstance> sourceInstanceMap = sourceInstances.stream().collect(Collectors.toMap(TIndicatorsInstance::getId, Function.identity()));
        //2获取对应的资产下的组件和实例
        List<TAssetIndicatorsModule> indicatorsModules = assetIndicatorsModuleService.getByCalAssetIds(parentIds);
        Collection<AssetIndicatorsInstanceVO> instanceVOS = assetIndicatorsInstanceService.listVOByCalAssetIds(parentIds);
        Map<Long, List<AssetIndicatorsInstanceVO>> targetInstancesMap = ListUtil.groupList(instanceVOS, AssetIndicatorsInstanceVO::getCalAssetId);
        //获取config
        List<TAssetCalLabelConfigVO> assetCalLabelConfigs = assetCalLabelConfigService.queryLabelListByCalAssetIds(parentIds, instanceTableName);

        //获取表达式
        List<TAssetExpressionVO> assetExpressions = assetExpressionService.queryListByAssetIds(parentIds, instanceTableName);
        Map<Long, List<TAssetIndicatorsModule>> targetMap = new HashMap<>();
        //初始化
        calAssets.forEach(asset -> targetMap.put(asset.getId(), Lists.newArrayList()));
        targetMap.putAll(ListUtil.groupList(indicatorsModules, TAssetIndicatorsModule::getCalAssetId));


        //对比-组件和实例的关联字段
        targetMap.forEach((assetId, targetModules) -> {
            sourceMap.forEach((sourceModule, sourceInstanceList) -> {
                Optional<TAssetIndicatorsModule> first = targetModules.stream().filter(m -> Objects.equals(m.getTemplateModuleId(), sourceModule.getId())).findFirst();
                TAssetIndicatorsModule newTargetModule = first.orElseGet(TAssetIndicatorsModule::new);
                MyBeanUtil.doCopy(sourceModule, newTargetModule,
                        Setter.set(newTargetModule::setId, newTargetModule.getId()),
                        Setter.set(newTargetModule::setCalAssetId, assetId),
                        Setter.set(newTargetModule::setTemplateModuleId, sourceModule.getId()));
                List<TAssetIndicatorsInstance> targetInstancesList = targetInstancesMap.getOrDefault(assetId, Lists.newArrayList()).stream().map(a -> (TAssetIndicatorsInstance) a).collect(Collectors.toList());
                map.put(newTargetModule, getNewTargetInstances(targetInstancesList, sourceInstanceList, newTargetModule, TAssetIndicatorsInstance.class));

            });
        });
        if (map.isEmpty()) return;

        //修改数据
        assetIndicatorsModuleService.saveOrUpdateBatch(map.keySet());
        map.forEach((module, instances) -> instances.forEach(instance -> instance.setModuleId(module.getId())));
        List<TAssetIndicatorsInstance> saveInstances = map.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
        if (saveInstances.isEmpty()) return;
        assetIndicatorsInstanceService.saveOrUpdateBatch(saveInstances);

        //资产表达式和虚拟变量通用操作
        labelConfigAndExpressionHandle(sourceLabelConfigs, sourceExpressions, assetCalLabelConfigs, assetExpressions, saveInstances, instanceTableName, assetExpressionService, assetCalLabelConfigService);

        List<Long> instanceIds = saveInstances.stream().map(TAssetIndicatorsInstance::getId).collect(Collectors.toList());
        //删除组件内不等于-1的实例数据,级联删除
        List<TAssetIndicatorsInstance> delInstances = assetIndicatorsInstanceService.list(Wrappers.
                <TAssetIndicatorsInstance>lambdaQuery().
                in(TAssetIndicatorsInstance::getModuleId, map.keySet().stream().map(TAssetIndicatorsModule::getId).collect(Collectors.toList())).
                ne(TAssetIndicatorsInstance::getTemplateInstanceId, -1).
                notIn(TAssetIndicatorsInstance::getId, instanceIds)
        );
        if (!delInstances.isEmpty()) {
            commonService.delete(DeleteBody.of(delInstances.stream().map(TAssetIndicatorsInstance::getId).collect(Collectors.toSet()), instanceTableName));
        }
    }

}
